package scu.maqiang.mesh;

import static java.lang.Math.abs;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;

import scu.maqiang.numeric.*;

public class Mesh3H8 extends Mesh {
	public Mesh3H8() {
		super();
		nDim =3;
		nPerElement = 8;
		nPerBoundary = 4;
		nBoundaryPerElement = 6;
		nEdgePerElement = 12;
		nEdgePerBoundary = 4;
		tecplotType = "FEBRICK";
		meditMeshType = new String[]{"Vertices", "Hexahedra", "Quadrilaterals"};
		gmshType = new String[]{"SH", "VH", "TH"};
		gmshElementType = 5;
	}

	public Mesh3H8 cube(int xNum, int yNum, int zNum) {
		int xNodes = xNum + 1;
		int yNodes = yNum + 1;
		int zNodes = zNum + 1;
		nv = xNodes * yNodes * zNodes;
		nt = xNum * yNum * zNum;
		nb = 2 * (xNum * yNum + yNum * zNum + xNum * zNum);
		initMesh0(nv, nt, nb);
		int count = 0;
		for (int k = 0; k < zNodes; k++) {
			for (int j = 0; j < yNodes; j++) {
				for (int i = 0; i < xNodes; i++) {
					nodes[count++] = new double[] {(i + 0.0) / xNum, (j + 0.0) / yNum, (k + 0.0) / zNum};
				}
			}
		}

		count = 0;
		int L1, L2, L3, L4, L5, L6, L7, L8;
		for (int k = 0; k < zNum; k++) {
			for (int j = 0; j < yNum; j++) {
				for (int i = 0; i < xNum; i++) {
					L1 = i + j * xNodes + k * xNodes * yNodes;
					L2 = L1 + 1;
					L3 = L2 + xNodes;
					L4 = L3 - 1;
					int temp = xNodes * yNodes;
					L5 = L1 + temp;
					L6 = L2 + temp;
					L7 = L3 + temp;
					L8 = L4 + temp;
					elements[count++] = new int[] {L1, L2, L3, L4, L5, L6, L7, L8};
				}
			}
		}

		// ����z = 0��ı߽���Ϊ1
		count = 0;
		for (int j = 0; j < yNum; j++) {
			for (int i = 0; i < xNum; i++) {
				L1 = i + j * xNodes;
				L2 = L1 + 1;
				L3 = L2 + xNodes;
				L4 = L3 - 1;
				boundaries[count] = new int[] {L1, L4, L3, L2};
				boundaryLabel[count++] = 1;
			}
		}

		// ����z = 1��ı߽���Ϊ2
		for (int j = 0; j < yNum; j++) {
			for (int i = 0; i < xNum; i++) {
				int temp = zNum * xNodes * yNodes;
				L1 = i + j * xNodes + temp;
				L2 = L1 + 1;
				L3 = L2 + xNodes;
				L4 = L3 - 1;
				boundaries[count] = new int[] {L1, L2, L3, L4};
				boundaryLabel[count++] = 2;
			}
		}

		// ����x = 0��߽���Ϊ3
		for (int j = 0; j < zNum; j++) {
			for (int i = 0; i < yNum; i++) {
				L1 = i * xNodes + j * xNodes * yNodes;
				L2 = L1 + xNodes;
				L3 = L2 + xNodes * yNodes;
				L4 = L1 + xNodes * yNodes;
				boundaries[count] = new int[] {L1, L4, L3, L2};
				boundaryLabel[count++] = 3;
			}
		}

		// ����x = 1��߽���Ϊ4
		for (int j = 0; j < zNum; j++) {
			for (int i = 0; i < yNum; i++) {
				L1 = xNum + i * xNodes + j * xNodes * yNodes;
				L2 = L1 + xNodes;
				L3 = L2 + xNodes * yNodes;
				L4 = L1 + xNodes * yNodes;
				boundaries[count] = new int[] {L1, L2, L3, L4};
				boundaryLabel[count++] = 4;
			}
		}

		// ����y = 0��߽���Ϊ5
		for (int j = 0; j < zNum; j++) {
			for (int i = 0; i < xNum; i++) {
				L1 = i + j * xNodes * yNodes;
				L2 = L1 + 1;
				L3 = L2 + xNodes * yNodes;
				L4 = L3 - 1;
				boundaries[count] = new int[] {L1, L2, L3, L4};
				boundaryLabel[count++] = 5;
			}
		}

		// ����y = 1��߽���Ϊ6
		for (int j = 0; j < zNum; j++) {
			for (int i = 0; i < xNum; i++) {
				int temp = yNum * xNodes;
				L1 = i + j * xNodes * yNodes + temp;
				L2 = L1 + 1;
				L3 = L2 + xNodes * yNodes;
				L4 = L3 - 1;
				boundaries[count] = new int[] {L1, L4, L3, L2};
				boundaryLabel[count++] = 6;
			}
		}
		return this;
	}

	public Mesh3H8 generateSAWMesh() {
		//Mesh3H8 mesh = new Mesh3H8();
		double lambda = 1682;
		double pitch = 841;
		double elWidth = 420.5;
		double hElectr = 200;
		double hAir = pitch - hElectr;
		double hLiTaO3 = 600;
		double hSubstr = 33640;
		int N_IDT = 200;
		double Aperture = 15.652;
		double hSiO2 = 500;
		double D_Y = pitch;
		System.out.println("lambda " + lambda + " pitch " + pitch + " elWidth " + elWidth + " hElectr "
				+ hElectr + " hpiE " + hLiTaO3 + " hSiO2 " + hSiO2 + " hSubstr " + hSubstr);

		int n_Si = 250;
		int n_SiO2 = 20;
		int n_LiTaO3 = 20;
		int n_Hel = 10;
		int n_Air = 20;
		int n_W1 = 10;
		int n_Wele = 20;
		int n_Y = 1;
		int n_bottom = 2 * n_W1 + n_Wele;

		double d_x_W1 = (pitch - elWidth) / (2 * n_W1);
		double d_x_electr = elWidth / n_Wele;
		System.out.println("d_x_W1 = " + d_x_W1);
		System.out.println("d_x_electr = " + d_x_electr);

		//X坐标
		int Nsize = n_W1 * 2 + n_Wele + 1;
		System.out.println("Nsize = " + Nsize);
		double[] node_coord_X = new double[Nsize];
		int i_node = 0;
		for(int j = 0; j < n_W1 + 1; j++) {  //循环n_W1 + 1次
			node_coord_X[i_node++] = d_x_W1 * j;
		}
		for(int j = 1; j < n_Wele + 1; j++) {  //循环n_Wele次
			node_coord_X[i_node++] = d_x_W1 * n_W1 + d_x_electr * j;
		}
		for(int j = 1; j < n_W1 + 1; j++) {   //循环n_W1次
			node_coord_X[i_node++] = d_x_W1 * n_W1 + d_x_electr * n_Wele + d_x_W1 * j;
		}
		System.out.println("Coord X: ");
		System.out.println(MVO.toString(node_coord_X));


		//Z坐标
		double dz_Si = hSubstr / n_Si;
		System.out.println("dz_Si = " + dz_Si);
		double dz_SiO2 = hSiO2 / n_SiO2;
		System.out.println("dz_SiO2 = " + dz_SiO2);
		double dz_LiTaO3 =hLiTaO3 / n_LiTaO3;
		System.out.println("dz_LiTaO3 = " + dz_LiTaO3);
		double dz_Electr = hElectr / n_Hel;
		System.out.println("dz_Electr = " + dz_Electr);
		double dz_Air = hAir / n_Air;
		System.out.println("dz_Air = " + dz_Air);

		Nsize = n_Si + n_SiO2 + n_LiTaO3 + n_Hel + n_Air + 1;
		System.out.println("Nsize = " + Nsize);
		double[] node_coord_Z = new double[Nsize];
		double offset = 0;
		i_node = 0;
		for(int i = 0; i < n_Si + 1; i++) { //循环n_Si + 1次
			node_coord_Z[i_node++] = dz_Si * i;
		}
		offset = dz_Si * n_Si;
		for(int i = 1; i < n_SiO2 + 1; i++) {//循环n_SiO2次
			node_coord_Z[i_node++] = offset + dz_SiO2 * i;
		}
		offset += dz_SiO2 * n_SiO2;
		for(int i = 1; i < n_LiTaO3 + 1; i++) {//循环n_LiTaO3次
			node_coord_Z[i_node++] = offset + dz_LiTaO3 * i;
		}
		offset += dz_LiTaO3 * n_LiTaO3;
		for(int i = 1; i < n_Hel + 1; i++) {//循环n_Hel次
			node_coord_Z[i_node++] = offset + dz_Electr * i;
		}
		offset += dz_Electr * n_Hel;
		for(int i = 1; i < n_Air + 1; i++) {//循环n_Air次
			node_coord_Z[i_node++] = offset + dz_Air * i;
		}
		System.out.println("Coord Z: ");
		System.out.println(MVO.toString(node_coord_Z));

		double dy = D_Y/n_Y;
		double[] node_coord_Y = new double[n_Y + 1];
		for(int i = 0; i < n_Y + 1; i++) {
			node_coord_Y[i] = i * dy;
		}
		System.out.println("Coord Y:");
		System.out.println(MVO.toString(node_coord_Y));

		int N_nodeX = node_coord_X.length;
		int N_nodeY = node_coord_Y.length;
		int N_nodeZ = node_coord_Z.length;
		ArrayList<int[]> node_dof = new ArrayList<>();

		ArrayList<Integer> dof_type = new ArrayList<>();
		i_node = -1;
		int i_dof = 0;
		for(int i_nodeY = 0; i_nodeY < N_nodeY; i_nodeY++) {
			//Si, SiO2, LiTaO3
			for(int i_nodeZ = 0; i_nodeZ < n_Si + n_SiO2 + n_LiTaO3 + 1; i_nodeZ++) {
				for(int i_nodeX = 0; i_nodeX < N_nodeX; i_nodeX++) {
					i_node++;
					node_dof.add(new int[]{i_dof, i_dof + 1, i_dof + 2, i_dof + 3});
					dof_type.add(0);
					dof_type.add(1);
					dof_type.add(2);
					dof_type.add(3);
					i_dof += 4;
				}
			}
			for(int i_nodeZ = 0; i_nodeZ < n_Hel; i_nodeZ++) {
				for (int i_nodeX = 0; i_nodeX < n_W1; i_nodeX++) {
					i_node++;
					node_dof.add(new int[]{i_dof});
					dof_type.add(0);
					i_dof++;
				}
				for (int i_nodeX = 0; i_nodeX < n_Wele + 1; i_nodeX++) {
					i_node++;
					node_dof.add(new int[]{i_dof, i_dof + 1, i_dof + 2, i_dof + 3});
					dof_type.add(0);
					dof_type.add(1);
					dof_type.add(2);
					dof_type.add(3);
					i_dof += 4;
				}
				for (int i_nodeX = 0; i_nodeX < n_W1; i_nodeX++) {
					i_node++;
					node_dof.add(new int[]{i_dof});
					dof_type.add(0);
					i_dof++;
				}
			}

			for(int i_nodeZ = 0; i_nodeZ < n_Air; i_nodeZ++) {
				for (int i_nodeX = 0; i_nodeX < N_nodeX; i_nodeX++) {
					i_node++;
					node_dof.add(new int[]{i_dof});
					dof_type.add(0);
					i_dof++;
				}
			}
		}

//		for(int i = 0; i < node_dof.size(); i++) {
//			System.out.println(Arrays.toString(node_dof.get(i)));
//		}
		int N_dof = dof_type.size();
		System.out.println("N_dof = " + N_dof);
		i_node = -1;
		ArrayList<double[]> dof_coord = new ArrayList<>();
		for(int i = 0; i < N_dof; i++) {
			dof_coord.add(new double[3]);
		}
		int nv = N_nodeX * N_nodeY * N_nodeZ;
		double[][] nodes = new double[nv][3];
		int nodeIdx = 0;
		for(int i_nodeY = 0; i_nodeY < N_nodeY; i_nodeY++) {
			for(int i_nodeZ = 0; i_nodeZ < N_nodeZ; i_nodeZ++) {
				for(int i_nodeX = 0; i_nodeX < N_nodeX; i_nodeX++) {
					i_node++;
					nodes[nodeIdx][0] = node_coord_X[i_nodeX];
					nodes[nodeIdx][1] = node_coord_Y[i_nodeY];
					nodes[nodeIdx++][2] = node_coord_Z[i_nodeZ];
					int N_dofs = node_dof.get(i_node).length;
					for(int i = 0; i < N_dofs; i++) {
						int ii_dof = node_dof.get(i_node)[i];
						double[] coord = dof_coord.get(ii_dof);
						coord[0] = node_coord_X[i_nodeX];
						coord[1] = node_coord_Y[i_nodeY];
						coord[2] = node_coord_Z[i_nodeZ];
						//System.out.println(Arrays.toString(coord));
					}
				}
			}
		}

		//System.out.println(MVO.toString(nodes[1]));
		//System.out.println(dof_coord.size());
//		for(int i = 0; i < dof_coord.size(); i++) {
//			System.out.println(Arrays.toString(dof_coord.get(i)));
//		}

		//System.out.println(Arrays.toString(dof_coord.get(0)));

		int i_element = 0;
		int NX = n_W1 + n_Wele + n_W1 + 1;
		int NY = n_Y + 1;
		int NZ = n_Si + n_SiO2 + n_LiTaO3 + n_Hel + n_Air + 1;
		int NXNZ = NX * NZ;
		ArrayList<int[]> element_node = new ArrayList<>();
		for(int i_elementY = 0; i_elementY < n_Y; i_elementY++) {
			for(int i_elementZ = 0; i_elementZ < n_Si + n_SiO2 + n_LiTaO3 + n_Hel + n_Air; i_elementZ++) {
				for(int i_elementX = 0; i_elementX < n_W1 + n_Wele + n_W1; i_elementX++) {
					int[] element = new int[8];
					element[0] = i_elementY * NXNZ + i_elementZ * NX + i_elementX;
					element[1] = element[0] + 1;

					element[2] = element[0] + NXNZ + 1;
					element[3] = element[2] - 1;

					element[4] = element[0] + NX;
					element[5] = element[1] + NX;

					element[6] = element[2] + NX;
					element[7] = element[3] + NX;
					element_node.add(element);
				}
			}
		}

		int nt = element_node.size();
		int[][] elements = new int[nt][];
		for(int i = 0; i < nt; i++) {
			elements[i] = element_node.get(i);
		}
//		for(int i = 0; i < element_node.size(); i++) {
//			System.out.println(Arrays.toString(element_node.get(i)));
//		}
		System.out.println("N_nodeX = " + N_nodeX);
		System.out.println("N_nodeY = " + N_nodeY);
		System.out.println("N_nodeZ = " + N_nodeZ);

		return constructMesh(nodes, elements);
	}

	public static void main(String[] args) {
		double lambda = 1682;
		double pitch = 841;
		double elWidth = 420.5;
		double hElectr = 200;
		double hAir = pitch - hElectr;
		double hLiTaO3 = 600;
		double hSubstr = 33640;
		int N_IDT = 200;
		double Aperture = 15.652;
		double hSiO2 = 500;

		Mesh3H8 SAWMesh = new Mesh3H8().generateSAWMesh();

		ScalarFunc SiRegion = (xyz, label, param) -> xyz[2] < 33640?1.0:-1.0;
		SAWMesh.setDomainLabel(SiRegion, null, 1);
		ScalarFunc SiO2Region = (xyz, label, param) -> xyz[2] > hSubstr  && xyz[2] < (hSubstr + hSiO2)? 1.0:-1.0;
		SAWMesh.setDomainLabel(SiO2Region, null, 2);
		ScalarFunc LiTaO3Region = (xyz, label, param) -> xyz[2] > (hSubstr + hSiO2) && xyz[2] < (hSubstr + hSiO2 + hLiTaO3) ?1.0:-1.0;
		SAWMesh.setDomainLabel(LiTaO3Region, null, 3);
		ScalarFunc ElectrRegion = (xyz, label, param) -> {
			double x = xyz[0], z = xyz[2];
			if (z > hSubstr + hSiO2 + hLiTaO3 && z < hSubstr + hSiO2 + hLiTaO3 + hElectr
					&& x > 210.25 && x < 210.25 + elWidth) {
				return 1.0;
			}
			return -1.0;
		};
		SAWMesh.setDomainLabel(ElectrRegion, null, 4);

		ScalarFunc AirRegion = (xyz, label, param) -> label == 0 ? 1:-1;
		SAWMesh.setNodeLabel(AirRegion, null, 1);
		ScalarFunc nonAirRegion = (xyz, label, param) -> -1.0 * AirRegion.action(xyz, label, param);
		SAWMesh.setNodeLabel(nonAirRegion, null, 4);
		ArrayList<Integer> eles = SAWMesh.getElements(ElectrRegion, null);
		System.out.println("Electric elments: " + eles.size());
		for(Integer idx:eles) {
			System.out.print(idx + "  ");
		}
		System.out.println("");

		ScalarFunc nodeLeftY1Line = (xyz, label, param) -> Math.abs(xyz[0]) < Constants.Er && Math.abs(xyz[1]) < Constants.Er?1.0:-1.0;
		ArrayList<Integer> nodeLeftY1 = SAWMesh.getNodes(nodeLeftY1Line, null);
		System.out.println("Node left Y1: " + nodeLeftY1.size());
		for(Integer idx:nodeLeftY1) {
			System.out.print(idx + "  ");
		}
		System.out.println("");

		ScalarFunc nodeRightY1Line = (xyz, label, param) -> Math.abs(xyz[0]- 841.0) < Constants.Er && Math.abs(xyz[1]) < Constants.Er?1.0:-1.0;
		ArrayList<Integer> nodeRightY1 = SAWMesh.getNodes(nodeRightY1Line, null);
		System.out.println("Node right Y1: " + nodeRightY1.size());
		for(Integer idx:nodeRightY1) {
			System.out.print(idx + "  ");
		}
		SAWMesh.saveMesh(MeshFormat.msh, "SAWMesh.msh");

		//SAWMesh.toTecplot("MySAWMesh.dat");
	}

	public Mesh3H8 constructMesh(double[][] nodes, int[][] eles) {
		nv = nodes.length;
		nt = eles.length;
		nodes = new double[nv][];
		nodeLabel = new int[nv];
		elements = new int[nt][];
		elementLabel = new int[nt];
		for(int i = 0; i < nv; i++) {
			nodes[i] = nodes[i].clone();
		}
		for(int i = 0; i < nt; i++) {
			elements[i] = eles[i].clone();
		}
		extractBoundarysFromElements();
		return this;
	}

	
	public Mesh3H8 add(Mesh3H8 meshB) {
	    int[] newNodesB, newBdB, ABd;
	    double tol = 1.0e-3, xA, yA, zA, xB, yB, zB;
	    int i, j, nvA, nvB, nConnected, n, nBd;
	    int[] idx = new int[4];
	    int[] idx2 = new int[4];
	    int[] temp = new int[4];
	    newNodesB = new int[meshB.nv];
	    newBdB = new int[meshB.nb];
	    ABd = new int[nb];
	    Arrays.fill(newNodesB, -1);
	    Arrays.fill(newBdB, -1);
	    Arrays.fill(ABd, -1);
	    nvA = nv;
	    nvB = meshB.nv;
	    for(i = 0; i < nvA; i++) {
	        xA = nodes[i][0];
	        yA = nodes[i][1];
	        zA = nodes[i][2];
	        for(j = 0; j < nvB; j++) {
	            xB = meshB.nodes[j][0];
	            yB = meshB.nodes[j][1];
	            zB = meshB.nodes[j][2];
	            if (abs(xA - xB) < tol && abs(yA - yB) < tol && abs(zA - zB) < tol) {
	                newNodesB[j] = i;
	                break;
	            }
	        }
	    }

	    for(i = 0; i < meshB.nb; i++) {
	        idx = meshB.boundaries[i];
	        temp[0] = newNodesB[idx[0]];
	        temp[1] = newNodesB[idx[1]];
	        temp[2] = newNodesB[idx[2]];
	        temp[3] = newNodesB[idx[3]];
	        UnorderIntArray uia1 = new UnorderIntArray(temp);
	        if (temp[0] > -1 && temp[1] > -1 && temp[2] > -1 && temp[3] > -1) {
	            newBdB[i] = 1;
	            for(j = 1; j < nb; j++) {
	                idx2 = boundaries[j];
	                UnorderIntArray uia2 = new UnorderIntArray(idx2);
	                if (uia1.equals(uia2)) {
	                	ABd[j] = 1;
	                    break;
	                }
	            }
	        }
	    }

	    //nConnected = (int)(IntStream.of(newNodesB).filter(iidx -> iidx != -1).count());
	    //nBd = (int)(IntStream.of(newBdB).filter(iidx -> iidx != -1).count());
	    nConnected = 0;
	    n = nvA;
	    for(i = 0; i < nvB; i++) {
	        //���B�еĽ��û����A�еĽ����ԣ�����������B�еĽ�����µ������еĽ����
	        if (newNodesB[i] == -1) {
	            newNodesB[i] = n;
	            n++;
	        }else {
	        	//����Ѿ���ԣ����������ԵĽ��ĸ���
	        	nConnected++;
	        }
	            
	    }
	    
	    nBd = 0;
	    n = nb;
	    for(i = 0; i < meshB.nb; i++) {
	    	if (newBdB[i] == -1) {
	            newBdB[i] = n;
	            n++;
	    	}
	        else {
	            nBd++;
	        }
	    }
	    
	    nv = nvA + nvB - nConnected;
	    int ntA = nt;
	    nt = ntA + meshB.nt;
	    int nbA = nb;
	    nb = nb + meshB.nb - nBd;
	    double[][] newNodes = new double[nv][];
	    int[] newNodeLabel = new int[nv];
	    int[][] newElements = new int[nt][];
	    int[] newElementLabel = new int[nt];
	    int[][] newBoundarys = new int[nb][];
	    int[] newBoundaryLabel = new int[nb];
	    for(i = 0; i < nvA; i++) {
	    	newNodes[i] = this.nodes[i];
	    	newNodeLabel[i] = this.nodeLabel[i];
	    }
	    
	    int count = nvA;
	    for(i = 0; i < nvB; i++) {
	    	if (newNodesB[i] > nvA - 1) {
	    		double[] node = meshB.nodes[i];
	    		newNodes[count++] = node;
	    	}
	    }
	    
	    for(i = 0; i < ntA; i++) {
	    	newElements[i] = this.elements[i];
	    }

	    count = ntA;
	    for(i = 0; i < meshB.nt; i++) {
	    	newElements[count] = meshB.elements[i];
	    	newElementLabel[count] = meshB.elementLabel[i];	    	
	    }
	    
	    for(i = 0; i < nbA; i++) {
	    	if (ABd[i] == 1) { 
	    		boundaryLabel[i] = 0;
	    	}
	    	newBoundarys[i] = boundaries[i];
	    	newBoundaryLabel[i] = boundaryLabel[i];
	    }
	    
	    
	    count = nbA;
	    for(i = 0; i < meshB.nb; i++) {
	    	if (newBdB[i] != 1) {
	    		int[] li = meshB.boundaries[i];
	    		int[] newEle = new int[4];
	    		for(int kk = 0; kk < 4; kk++) {
	    			newEle[kk] = newNodesB[li[kk]];
	    		}
	    		newBoundarys[count] = newEle;
	    		newBoundaryLabel[count] = meshB.boundaryLabel[i];
	    	}
	    }
	    this.nodes = newNodes;
	    this.nodeLabel = newNodeLabel;
	    this.elements = newElements;
	    this.elementLabel = newElementLabel;
	    this.boundaries = newBoundarys;
	    this.boundaryLabel = newBoundaryLabel;
		return this;
	}
	
	public Mesh3H8 add(Mesh3H8... mesh) {
		for(int i = 0; i < mesh.length; i++) {
			this.add(mesh[i]);
		}
		return this;
	}
	
	@Override
	public double[] getinteriorPointInElement(double[][] coord) {
		double[] x = new double[8];
		double[] y = new double[8];
		double[] z = new double[8];
		for (int i = 0; i < 8; i++) {
			x[i] = coord[i][0];
			y[i] = coord[i][1];
			z[i] = coord[i][2];
		}
		return new double[]{ MVO.average(x), MVO.average(y), MVO.average(z)};
	}

	@Override
	public double[] getinteriorPointOnBoundary(double[][] coord) {
		double[] x = new double[4];
		double[] y = new double[4];
		double[] z = new double[4];
		for (int i = 0; i < 4; i++) {
			x[i] = coord[i][0];
			y[i] = coord[i][1];
			z[i] = coord[i][2];
		}
		return new double[]{ MVO.average(x), MVO.average(y), MVO.average(z)};
	}
	
	@Override
	public boolean checkMesh(double[][] coord) {
		return CG.volume3DH8(coord) > 0;
	}

	@Override
	public int[][] getBoundarysFromElement(int i) {
		int[][] boundarys = new int[nBoundaryPerElement][];
		int[] ele = elements[i];
		boundarys[0] = new int[] {ele[0], ele[3], ele[2], ele[1]};
		boundarys[1] = new int[] {ele[4], ele[5], ele[6], ele[7]};
		boundarys[2] = new int[] {ele[0], ele[1], ele[5], ele[4]};
		boundarys[3] = new int[] {ele[2], ele[3], ele[7], ele[6]};
		boundarys[4] = new int[] {ele[0], ele[4], ele[7], ele[3]};
		boundarys[5] = new int[] {ele[1], ele[2], ele[6], ele[5]};
		return boundarys;
	}
	
	public SIMatrix renumberingEdges() {
        int ii1, jj1, kk1, ll1, ii2, jj2, kk2, ll2;
        SIMatrix A = new SIMatrix(nv);
        for (int i = 0; i < nt; i++) {
        	int[] ele = elements[i];
            ii1 = ele[0];
            jj1 = ele[1];
            kk1 = ele[2];
            ll1 = ele[3];
            ii2 = ele[4];
            jj2 = ele[5];
            kk2 = ele[6];
            ll2 = ele[7];
            A.addElement(ii1, jj1, -1);
            A.addElement(jj1, ii1, -1);
            A.addElement(jj1, kk1, -1);
            A.addElement(kk1, jj1, -1);
            A.addElement(kk1, ll1, -1);
            A.addElement(ll1, kk1, -1);
            A.addElement(ll1, ii1, -1);
            A.addElement(ii1, ll1, -1);

            A.addElement(ii2, jj2, -1);
            A.addElement(jj2, ii2, -1);
            A.addElement(jj2, kk2, -1);
            A.addElement(kk2, jj2, -1);
            A.addElement(kk2, ll2, -1);
            A.addElement(ll2, kk2, -1);
            A.addElement(ll2, ii2, -1);
            A.addElement(ii2, ll2, -1);

            A.addElement(ii1, ii2, -1);
            A.addElement(ii2, ii1, -1);
            A.addElement(jj1, jj2, -1);
            A.addElement(jj2, jj1, -1);
            A.addElement(kk1, kk2, -1);
            A.addElement(kk2, kk1, -1);
            A.addElement(ll1, ll2, -1);
            A.addElement(ll2, ll1, -1);
        }
        
        A.sort();
        SIMatrix B = A.triU();
        int nb = B.getNNZ();
        int[] iIdx = new int[nb];
        int[] jIdx = new int[nb];
        int[] values = new int[nb];
        B.getTriValues(iIdx, jIdx, values);
        for (int i = 0; i < nb; i++) {
            values[i] = i + 1;
        }
        SIMatrix C = new SIMatrix(iIdx, jIdx, values, nv, nv);
        return C;
    }


//	@Override
//	public void setBoundaries(HashSet<UnorderIntArray> set) {
//		this.nb = set.size();
////		for(UnorderIntegerArray ele : set) {
////			this.boundarys.add(new Quadrilateral4(ele.getIntSet(), 0));
////		}
//	}


	@Override
	public int getTecplotNt() {
		return nt;
	}


	@Override
	public int[][] getEdgesFromElement(int i) {
		int[][] result = new int[12][];
		int[] ele = elements[i];
		result[0] = new int[] {ele[0], ele[1]};
		result[1] = new int[] {ele[1], ele[2]};
		result[2] = new int[] {ele[2], ele[3]};
		result[3] = new int[] {ele[3], ele[0]};
		result[4] = new int[] {ele[4], ele[5]};
		result[5] = new int[] {ele[5], ele[6]};
		result[6] = new int[] {ele[6], ele[7]};
		result[7] = new int[] {ele[7], ele[4]};
		result[8] = new int[] {ele[0], ele[4]};
		result[9] = new int[] {ele[1], ele[5]};
		result[10] = new int[] {ele[2], ele[6]};
		result[11] = new int[] {ele[3], ele[7]};
		return result;
	}
}
